﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace System.Common.Native
{
  public class DynamicLibrary : IDisposable
  {
    private readonly string fDllName;
    private IntPtr fHandle = IntPtr.Zero;

    public DynamicLibrary( string dllName )
    {
      fDllName = dllName;

      if ( !File.Exists( fDllName ) )
        fDllName = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, dllName );

      if ( !File.Exists( fDllName ) )
      {
        fDllName = null;

        return;
      }

      fHandle = Kernel.LoadLibrary( fDllName );
    }

    public bool Valid
    {
      get { return fHandle != IntPtr.Zero; }
    }

    public string LibraryPath { get { return fDllName; } }

    public Delegate GetProc<T>( string procName )
    {
      if ( !Valid )
        return null;

      var addr = Kernel.GetProcAddress( fHandle, procName );
      return addr != IntPtr.Zero ? Marshal.GetDelegateForFunctionPointer( addr, typeof( T ) ) : null;
    }

    #region IDisposable Members

    public void Dispose()
    {
      if ( !Valid )
        return;

      var handle = fHandle;
      fHandle = IntPtr.Zero;

      Kernel.FreeLibrary( handle );
    }

    #endregion
  }
}
